//
//  GDPRefreshControl.swift
//  simpleWeibo
//
//  Created by sunmumu on 2018/12/28.
//  Copyright © 2018 孙林. All rights reserved.
//

import UIKit

private let GDPRefreshOffset: CGFloat = 125

enum GDPRefreshState {
    case Normal
    case Pulling
    case WillRefresh
}

class GDPRefreshControl: UIControl {
    // MARK: - 属性
    ///刷新控件的父视图, 下拉刷新控件应该适用于 UITableView/UICollectionView
    private weak var scrollView: UIScrollView?
    fileprivate lazy var refreshView: GDPRefreshview = GDPRefreshview.refreshView()
    
    override init(frame: CGRect) {
        super.init(frame: CGRect())
        setupUI()
        
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupUI()
    }
    
    /**
     willMove addSubview 方法会调用
     - 当添加到父视图的时候 newSuperview 是父视图
     - 当父视图被移除, newSuperview 是 nil
     */
    override func willMove(toSuperview newSuperview: UIView?) {
        super.willMove(toSuperview: newSuperview)
        guard let sv = newSuperview as? UIScrollView else {
            return
        }
        //记录父视图
        scrollView = sv
        
        //KVO 监听父视图的 contentOffset
        scrollView?.addObserver(self, forKeyPath: "contentOffset", options: [], context: nil)
    }
    
    //本视图从 父视图移除
    //提示: 所有的下拉刷新框架 都是通过监听父视图的 "contentOffset"
    //所有的框架的 kvo监听实现思路 都是这个
    override func removeFromSuperview() {
        //superview存在
        superview?.removeObserver(self, forKeyPath: "contentOffset")
        super.removeFromSuperview()
        //superview不存在
    }
    
    //所有KVO 会统一调用此方法
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        
        guard let sv = scrollView else {
            return
        }
        
        //初始高度 应该为 0
        let height = -(sv.contentInset.top + sv.contentOffset.y)
        // contentOffset.y 跟 contentInset 的 top 有关
        
        //height < 0 scrollView向上移动
        if height < 0 {
            return
        }
        
        //父视图的高度 传给refreshView 如果正在刷新中 不传递
        // 把代码 放在 '最合适的地方'
        if refreshView.refreshState != .WillRefresh {
            refreshView.parentViewHeight = height
        }
        
        //根据 height 设置刷新控件 的 frame
        self.frame = CGRect(x: 0, y: -height, width: sv.bounds.width, height: height)
        
        //判断临界点 只需要判断一次
        if sv.isDragging {
            if height >  GDPRefreshOffset && (refreshView.refreshState == .Normal) {
                print("放手刷新")
                refreshView.refreshState = .Pulling
            } else if height < GDPRefreshOffset && (refreshView.refreshState == .Pulling) {
                print("继续使劲...")
                refreshView.refreshState = .Normal
            }
        } else {
            //放手 - 判断是否超过临界点
            //超过临界点 刷新数据
            if refreshView.refreshState == .Pulling {
                beginRefreshing()
                sendActions(for: .valueChanged)
            }
        }
    }
    
    deinit {
        //移除KVO
        scrollView?.removeObserver(self, forKeyPath: "contentOffset")
    }
    
    func beginRefreshing() {
        print("开始刷新")
        
        //判断父视图
        guard let sv = scrollView else {
            return
        }
        
        //判断状态 正在刷新时 不允许再次调用 刷新方法
        if refreshView.refreshState == .WillRefresh {
            return
        }
        
        //设置刷新视图的状态
        refreshView.refreshState = .WillRefresh
        
        //让整个刷新视图能够显示出来
        //解决方法: 修改表格的contentInset
        var inset = sv.contentInset
        inset.top += GDPRefreshOffset
        sv.contentInset = inset
        
    }
    
    func endRefreshing() {
        print("结束刷新")
        guard let sv = scrollView else {
            return
        }
                                                                                                                                                       
        //判断状态 不是WillRefresh 就返回
        if refreshView.refreshState != .WillRefresh {
            return
        }
        
        //恢复刷新视图的状态
        refreshView.refreshState = .Normal
        
        //恢复表格视图的contentInset
        var inset = sv.contentInset
        inset.top -= GDPRefreshOffset
        sv.contentInset = inset
    }

}

extension GDPRefreshControl {
    fileprivate func setupUI() {
        backgroundColor = superview?.backgroundColor
        //添加刷新视图
        addSubview(refreshView)
        refreshView.translatesAutoresizingMaskIntoConstraints = false
        addConstraints([NSLayoutConstraint(item: refreshView,
                                           attribute: .centerX,
                                           relatedBy: .equal,
                                           toItem: self,
                                           attribute: .centerX,
                                           multiplier: 1.0,
                                           constant: 0)])
        addConstraints([NSLayoutConstraint(item: refreshView,
                                           attribute: .bottom,
                                           relatedBy: .equal,
                                           toItem: self,
                                           attribute: .bottom,
                                           multiplier: 1.0,
                                           constant: 0)])
        addConstraints([NSLayoutConstraint(item: refreshView,
                                           attribute: .width,
                                           relatedBy: .equal,
                                           toItem: nil,
                                           attribute: .notAnAttribute,
                                           multiplier: 1.0,
                                           constant: refreshView.bounds.width)])
        addConstraints([NSLayoutConstraint(item: refreshView,
                                           attribute: .height,
                                           relatedBy: .equal,
                                           toItem: nil,
                                           attribute: .notAnAttribute,
                                           multiplier: 1.0,
                                           constant: refreshView.bounds.height)])
    }
}
